#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
#include <stdbool.h>

#define GPIO_LINE 9
#define ALSA_PCM_NEW_HW_PARAMS_API

// 音频参数
#define SAMPLE_RATE 44100
#define CHANNELS 2
#define SAMPLE_SIZE 2 // 16-bit
#define BUFFER_SIZE 409600 // 缓冲区大小，单位是字节

// 录音函数声明
void start_recording();
void stop_recording();

// 全局变量
snd_pcm_t *capture_handle;
bool is_recording = false;
FILE *output_file;

int main(void) {
    struct gpiod_chip *chip;
    struct gpiod_line *line;
    int value, last_value;

    // 打开GPIO芯片
    chip = gpiod_chip_open_by_label("GPIOF");
    if (!chip) {
        perror("打开GPIO芯片失败");
        return 1;
    }

    // 获取GPIO线
    line = gpiod_chip_get_line(chip, GPIO_LINE);
    if (!line) {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 将GPIO线设置为输入模式
    if (gpiod_line_request_input(line, "key1")) {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 获取初始的GPIO线值
    last_value = gpiod_line_get_value(line);

    // 无限循环检测GPIO线值的变化
    while (1) {
        // 获取当前的GPIO线值
        value = gpiod_line_get_value(line);
        
        // 如果当前值与上一次的值不同，说明按键状态发生了变化
        if (value != last_value) {
            // 如果当前值为0，表示按键被按下
            if (value == 0) {
                printf("key pressed\n");
                if (!is_recording) {
                    start_recording();
                    is_recording = true;
                }
            } 
            // 如果当前值为1，表示按键被释放
            else {
                printf("key released\n");
                if (is_recording) {
                    stop_recording();
                    is_recording = false;
                }
            }
            // 更新上一次的值为当前值
            last_value = value;
        }
        
        // 如果正在录音，读取音频数据并保存到文件
        if (is_recording) {
            char buffer[BUFFER_SIZE];
            int frames = snd_pcm_readi(capture_handle, buffer, sizeof(buffer) / (SAMPLE_SIZE * CHANNELS));
            if (frames < 0) {
                frames = snd_pcm_recover(capture_handle, frames, 0);
            }
            if (frames < 0) {
                fprintf(stderr, "录音错误: %s\n", snd_strerror(frames));
            } else {
                fwrite(buffer, SAMPLE_SIZE, frames * CHANNELS, output_file);
            }
        }
        
        // 减少延时，以提高数据读取频率
        usleep(50000);
    }

    // 释放GPIO线资源
    gpiod_line_release(line);
    // 关闭GPIO芯片
    gpiod_chip_close(chip);
    return 0;
}

void start_recording() {
    int rc;
    snd_pcm_hw_params_t *params;
    unsigned int val = SAMPLE_RATE;
    int dir;
    snd_pcm_uframes_t frames;

    // 打开音频设备
    rc = snd_pcm_open(&capture_handle, "hw:0,1", SND_PCM_STREAM_CAPTURE, 0);
    if (rc < 0) {
        fprintf(stderr, "无法打开音频设备: %s\n", snd_strerror(rc));
        return;
    }

    // 分配硬件参数结构体
    snd_pcm_hw_params_alloca(&params);

    // 用默认值填充参数
    snd_pcm_hw_params_any(capture_handle, params);

    // 设置所需的硬件参数
    snd_pcm_hw_params_set_access(capture_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(capture_handle, params, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(capture_handle, params, CHANNELS);
    snd_pcm_hw_params_set_rate_near(capture_handle, params, &val, &dir);

    // 设置周期大小
    frames = 32;
    snd_pcm_hw_params_set_period_size_near(capture_handle, params, &frames, &dir);

    // 设置缓冲区大小
    snd_pcm_uframes_t buffer_size = 4 * frames;
    snd_pcm_hw_params_set_buffer_size_near(capture_handle, params, &buffer_size);

    // 将参数写入设备
    rc = snd_pcm_hw_params(capture_handle, params);
    if (rc < 0) {
        fprintf(stderr, "无法设置参数: %s\n", snd_strerror(rc));
        snd_pcm_close(capture_handle);
        return;
    }

    // 打开输出文件
    output_file = fopen("output.pcm", "wb");
    if (!output_file) {
        fprintf(stderr, "无法打开输出文件\n");
        snd_pcm_close(capture_handle);
        return;
    }

    printf("开始录音...\n");
}

void stop_recording() {
    printf("停止录音...\n");
    if (output_file) {
        fclose(output_file);
    }
    snd_pcm_close(capture_handle);
}
